//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
#pragma once

#include <XamlRuntime.h>

/// <summary>
/// The basic template implementation of a XRConverter.
/// IXRCustomConverter: used to convert and convert back the value.
/// </summary>
template <typename Impl>
class XRCustomConverter: public IXRCustomConverter
{
    BEGIN_QI_MAP()
        QI_MAP_INTERFACE(IXRCustomConverter)
    END_QI_MAP()

    /// <summary>
    /// Creation method for a given implementation, specified with the template
    /// argument Impl, of the XRConverter.
    /// </summary>
    /// <param name="pDependencyObject">Core representation of this XRConverter</param>
    /// <param name="id">ID of the type created</param>
    static HRESULT CALLBACK Create(
        __in IXRDependencyObject *pDependencyObject, 
        __in UINT id)
    {
        XRPtr<IXRConverter> pConverter;
        XRPtr<Impl> pCustomConverter;
        HRESULT hr = S_OK;

        if (NULL == pDependencyObject)
        {
            hr = E_INVALIDARG;
            goto Error;
        }

        pConverter = pDependencyObject;
        if (NULL == pConverter)
        {
            hr = E_UNEXPECTED;
            goto Error;
        }

        hr = XRObject<Impl>::CreateInstance(&pCustomConverter);
        if (FAILED(hr))
        {
            goto Error;
        }
        if (NULL == pCustomConverter)
        {
            hr = E_OUTOFMEMORY;
            goto Error;
        }

        hr = pConverter->SetCustomConverter(pCustomConverter);
        if (FAILED(hr))
        {
            goto Error;
        }

    Error:
        return hr;
    }

protected:

    /// <summary>
    /// Static data member for keeping the registered XRConverter ID.
    /// Note: after the XAML Runtime is uninitialized, this data member
    /// needs to be reset to 0. So that allow the user to call 'Register()'
    /// method again.
    /// </summary>
    static UINT s_CustomConverterID;

public:

    virtual HRESULT STDMETHODCALLTYPE Convert(
        __in XRValue *pValueIn, __in XRValue *pParameter, 
        __in XRValue *pCultureInfo, __out XRValue *pValueOut) = 0;
    virtual HRESULT STDMETHODCALLTYPE ConvertBack(
        __in XRValue *pValueIn, __in XRValue *pParameter, 
        __in XRValue *pCultureInfo, __out XRValue *pValueOut) = 0;

    /// <summary>
    /// Register an XRConverter to a specific namespace.
    /// If the XRConverter is successfully registered, a converter ID will be returned and stored 
    /// in the static data member 's_CustomConverterID'.
    /// </summary>
    /// <param name="pConverterName">The name of this XRConverter</param>
    /// <param name="pConverterNamespace">The namespace where the XRConverter register to</param>
    static HRESULT Register(
        __in const WCHAR *pConverterName, 
        __in const WCHAR *pConverterNamespace)
    {
        IXRApplicationPtr pApp;
        HRESULT hr = S_OK;

        hr = GetXRApplicationInstance(&pApp);
        if (FAILED(hr)) 
        {
            goto Error;
        }

        if (0 == s_CustomConverterID)
        {
            hr = pApp->RegisterXamlObject(
                __uuidof(Impl), pConverterName, pConverterNamespace, 
                Create, IID_IXRConverter, &s_CustomConverterID);
        }

    Error:
        return hr;
    }
};

template <typename Impl>
UINT XRCustomConverter<Impl>::s_CustomConverterID = 0;
